#include "./../inc/lcd.hpp"

LCD::LCD()
{
    lcd_width = 800;
    lcd_height = 480;
    lcd_init();
    lcd_mmap_init();
}

LCD::~LCD()
{
    munmap(lcd_mmap, lcd_width * lcd_height * 4);
    fclose(fp_lcd);
}

void LCD::lcd_init()
{
    fp_lcd = fopen("/dev/fb0", "r+");
    if (fp_lcd == NULL)
    {
        perror("lcd_fopen");
    }
    else
    {
        cout << "open lcd success" << endl;
    }
}

void LCD::lcd_mmap_init()
{
    // 从FILE指针获取文件描述符
    int fd_lcd = fileno(fp_lcd);
    if (fd_lcd < 0)
    {
        perror("fileno");
    }

    // 映射文件到内存
    lcd_mmap = (int *)mmap(NULL, lcd_width * lcd_height * 4, PROT_READ | PROT_WRITE, MAP_SHARED, fd_lcd, 0);

    printf("mmap success\n");
    memset(lcd_mmap, WHITE, lcd_width * lcd_height * 4);
    // memset(lcd_mmap, 0, lcd_width * lcd_height * 4);
}

int *LCD::get_lcd_mmap()
{
    return lcd_mmap;
}

int LCD::get_lcd_width()
{
    return lcd_width;
}

int LCD::get_lcd_height()
{
    return lcd_height;
}

void LCD::draw_circle_fast(int center_x, int center_y, int radius, int color)
{
    int SCREEN_WIDTH = 800;
    int SCREEN_HEIGHT = 480;

    int x = radius;
    int y = 0;
    int err = 0;
    int radius_sq = radius * radius;

    while (x >= y)
    { // 绘制八分之一的圆
        int y_plus = center_y + y;
        int y_minus = center_y - y;
        for (int i = -x; i <= x; i++)
        {
            int current_x = center_x + i;
            if (y_plus > 48 && y_plus < SCREEN_HEIGHT && current_x >= 0 && current_x < SCREEN_WIDTH)
            {
                lcd_mmap[y_plus * lcd_width + current_x] = color;
            }
            if (y_minus > 48 && y_minus < SCREEN_HEIGHT && current_x >= 0 && current_x < SCREEN_WIDTH)
            {
                lcd_mmap[y_minus * lcd_width + current_x] = color;
            }
        }

        int x_plus = center_y + x;
        int x_minus = center_y - x;
        for (int i = -y; i <= y; i++)
        {
            int current_x = center_x + i;
            if (x_plus > 48 && x_plus < SCREEN_HEIGHT && current_x >= 0 && current_x < SCREEN_WIDTH)
            {
                lcd_mmap[x_plus * lcd_width + current_x] = color;
            }
            if (x_minus > 48 && x_minus < SCREEN_HEIGHT && current_x >= 0 && current_x < SCREEN_WIDTH)
            {
                lcd_mmap[x_minus * lcd_width + current_x] = color;
            }
        }

        y++;
        err += 1 + 2 * y;
        if (2 * (err - x) + 1 > 0)
        {
            x--;
            err += 1 - 2 * x;
        }
    }

    // 填充圆形内部，增加屏幕边界检查
    for (int dy = -radius; dy <= radius; dy++)
    {
        int current_y = center_y + dy;
        // 检查y坐标是否在限制区域内且在屏幕范围内
        if (current_y > 48 && current_y < SCREEN_HEIGHT)
        {
            for (int dx = -radius; dx <= radius; dx++)
            {
                int current_x = center_x + dx;
                // 检查x坐标是否在屏幕范围内
                if (current_x >= 0 && current_x < SCREEN_WIDTH)
                {
                    if (dx * dx + dy * dy <= radius_sq)
                    {
                        lcd_mmap[current_y * lcd_width + current_x] = color;
                    }
                }
            }
        }
    }
}

// 快速绘制线段（Bresenham算法）  布雷森汉姆算法 or 布雷森算法
void LCD::draw_line_fast(int x1, int y1, int x2, int y2, int radius, int color)
{
    int dx = abs(x2 - x1);
    int dy = abs(y2 - y1);
    int sx = (x1 < x2) ? 1 : -1;
    int sy = (y1 < y2) ? 1 : -1;
    int err = dx - dy;

    while (1)
    {
        draw_circle_fast(x1, y1, radius, color);

        if (x1 == x2 && y1 == y2)
            break;

        int e2 = 2 * err;
        if (e2 > -dy)
        {
            err -= dy;
            x1 += sx;
        }
        if (e2 < dx)
        {
            err += dx;
            y1 += sy;
        }
    }
}